// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using Microsoft.TeamFoundation.Migration.Toolkit.VC;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.Migration.Toolkit;
using System.Diagnostics;

namespace Microsoft.Vsts.Rangers.Migration.TfsToTfs
{
    public class TfsToTfsAnalysisAlgorithms : TfsAnalysisAlgorithms
    {
        VersionControlSession m_session;

        protected override VersionControlSession Session
        {
            get
            {
                return m_session;
            }
        }

        public TfsToTfsAnalysisAlgorithms(VersionControlSession session)
        {
            if (session == null)
            {
                throw new ArgumentNullException("session");
            }

            m_session = session;
        }

        protected string GetMappedServerPath(string serverPath)
        {
            VersionControlMapping m = Util.FindAppropriateMappingForServerPath(serverPath, m_session);
            if (null == m)
            {
                return null;
            }

            return serverPath.Replace(m.Source, m.Target);
        }

        protected override IMigrationItem CreateMigrationItem(Item tfsItem)
        {
            if (tfsItem == null)
            {
                return null;
            }
            string mappedServerPath = GetMappedServerPath(tfsItem.ServerItem);

            if (!string.IsNullOrEmpty(mappedServerPath))
            {
                return new TfsMigrationItem(null, mappedServerPath, m_session);
            }

            return null;
        }

        protected override bool IsItemMapped(Item tfsItem)
        {
            string mappedServerPath = GetMappedServerPath(tfsItem.ServerItem);

            if (!string.IsNullOrEmpty(mappedServerPath))
            {
                return true;
            }

            return false;
        }

        #region Merge Functionality
        //---  This has moved into the base toolkit class...
        
        ///// <summary>
        ///// When not migrating history the merge bit alone is ignored.
        ///// </summary>
        ///// <param name="change">The change being processed</param>
        ///// <param name="grouping">The change grouing this change is to be a part of</param>
        //public override void Merge(Change change, ChangeGrouping grouping)
        //{
            
        //    validateChangeAndGroup(change, grouping);

        //    //Example Scenario:
        //    //Source:           $/TeamProject1/Source-branch
        //    //Target:           $/TeamProject1/Source
        //    //TargetSource:     $/TeamProject2/Source-branch
        //    //TargetTarget:     $/TeamProject2/Source


        //    IMigrationAction action = createMigrationAction(change.Item, grouping, ChangeAction.Merge);

        //    Item contributor = getMergeContributor(change.Item, false);

        //    action.ResolveType = MigrationMergeOptions.ResolveAutoMerge;

        //    action.TargetSourceItem = CreateMigrationItem(contributor);

        //    grouping.AddAction(action);

        //}


        ///// <summary>
        ///// Calls Merge and Edit to add the appropriate actions to the change grouping.
        ///// </summary>
        ///// <param name="change">The change being processed</param>
        ///// <param name="grouping">The change grouing this change is to be a part of</param>
        //public override void MergeEdit(Change change, ChangeGrouping grouping)
        //{
        //    Merge(change, grouping);


        //    //Why do we need to call edit?
        //    //Edit(change, grouping);
        //}
        //private Item getMergeContributor(Item item, bool getDownloadInfo)
        //{
        //    VersionSpec changeSpec = new ChangesetVersionSpec(item.ChangesetId);

        //    // TODO: overload that takes ItemSpec for deletion ids/etc.
        //    ChangesetMergeDetails mergeDetails = item.VersionControlServer.QueryMergesWithDetails(
        //        null,
        //        null,
        //        0,
        //        item.ServerItem,
        //        changeSpec,
        //        item.DeletionId,
        //        null,
        //        changeSpec,
        //        RecursionType.None);



        //    if (mergeDetails.MergedItems != null && mergeDetails.MergedItems.Length > 0)
        //    {
        //        ItemMerge latest = mergeDetails.MergedItems[0];
        //        foreach (ItemMerge im in mergeDetails.MergedItems)
        //        {
        //            // TODO: comparison based on target versions (cherry pick case)
        //            if (im.SourceVersionFrom > latest.SourceVersionFrom)
        //            {
        //                latest = im;
        //            }
        //        }

        //        return item.VersionControlServer.GetItem(latest.SourceItemId, latest.SourceVersionFrom, getDownloadInfo);
        //    }
        //    else
        //    {
        //        throw new MigrationException(string.Format(CultureInfo.InvariantCulture, "Unable to determine merge contributor for item {0}.  Expected to find at least 1 item - found 0", item.ServerItem));
        //    }
        //}

        #endregion

        #region Branch Functionality
        //---  This has moved into the base toolkit class...


        ///// <summary>
        ///// Because the default implementation does not migration integration history this calls Add to 
        ///// add the appropriate actions to the change grouping.
        ///// </summary>
        ///// <param name="change">The change being processed</param>
        ///// <param name="grouping">The change grouing this change is to be a part of</param>
        //public override void Branch(Change change, ChangeGrouping grouping)
        //{
        //    validateChangeAndGroup(change, grouping);

        //    //Example Scenario:
        //    //Source:           $/TeamProject1/Source
        //    //Target:           $/TeamProject1/Source-branch
        //    //TargetSource:     $/TeamProject2/Source
        //    //TargetTarget:     $/TeamProject2/Source-Branch


        //    //When this method is called, $/TeamProject1/Source-branch (Target) will be passed in as the change item.  We need to 
        //    //lookup the parent branch ($/TeamProject1/Source), and then use the normal procedure to create the target
        //    //migration items (TargetSource and TargetTarget).  Branch operations dont require a Source, just a TargetSource and TargetTarget.

        //    //Get the Branch parent for this item
        //    Item parentItem = GetBranchParent(change);

        //    //Create a Migration Item, using the parent as input (e.g. Parent is $/TeamProject/Source).
        //    TfsMigrationItem migItem = (TfsMigrationItem)CreateMigrationItem(parentItem);

        //    //Create a migration action, that will have the source populated as the original parent (e.g. Parent is $/TeamProject/Source)
        //    IMigrationAction action = createMigrationAction(change.Item, grouping, ChangeAction.Branch);

        //    //Set the TargetSource as the parent branch
        //    action.TargetSourceItem = (IMigrationItem)migItem;

        //    //SourceItem is not used for a Branch operation
        //    action.SourceItem = null;
        //    action.Recursive = false;

        //    //Need to find out if this item is in a folder that is already added (Workspace.PendBranch is recursive)
        //    if (!IsItemAlreadyAccountedForInParentFolder(migItem.ServerPath, grouping))
        //    {
        //        //It's not part of a folder that is already in the ChangeGrouping (branching a folder is always recursive), so add it
        //        grouping.AddAction(action);

        //        #region Debugging stuff

        //        System.Diagnostics.Debug.WriteLine("--------------");

        //        //  System.Diagnostics.Debug.WriteLine("Source: " + ((TfsMigrationItem)action.SourceItem).ServerPath);
        //        System.Diagnostics.Debug.WriteLine("TargetSourceItem: " + ((TfsMigrationItem)action.TargetSourceItem).ServerPath);
        //        System.Diagnostics.Debug.WriteLine("TargetTargetItem: " + ((TfsMigrationItem)action.TargetTargetItem).ServerPath);

        //        System.Diagnostics.Debug.WriteLine("--------------");

        //        #endregion

        //    }
        //}

        //private bool IsItemAlreadyAccountedForInParentFolder(string itemServerPath, ChangeGrouping grouping)
        //{
        //    bool folderFound = false;

        //    foreach (IMigrationAction savedAction in grouping.Actions)
        //    {
        //        if (savedAction.Action == ChangeAction.Branch)
        //        {
        //            if (itemServerPath.Contains(((TfsMigrationItem)savedAction.TargetSourceItem).ServerPath))
        //            {
        //                folderFound = true;
        //            }
        //        }
        //    }

        //    return folderFound;
        //}

        //private Item GetBranchParent(Change change)
        //{
        //    VersionControlServer tfsClient = change.Item.VersionControlServer;

        //    int changeId = (change.Item.DeletionId != 0) ? change.Item.ChangesetId - 1 : change.Item.ChangesetId;

        //    ChangesetVersionSpec version = new ChangesetVersionSpec(changeId);

        //    BranchHistoryTreeItem[][] history = tfsClient.GetBranchHistory(new ItemSpec[] { new ItemSpec(change.Item.ServerItem, RecursionType.None) }, version);

        //    BranchHistoryTreeItem item = history[0][0].GetRequestedItem();

        //    return item.Relative.BranchFromItem;
        //}

        #endregion

        #region Helper Methods
        //---  This has moved into the base toolkit class...

        //private void validateChangeAndGroup(Change change, ChangeGrouping grouping)
        //{
        //    if (change == null)
        //    {
        //        throw new ArgumentNullException("change");
        //    }

        //    if (grouping == null)
        //    {
        //        throw new ArgumentNullException("grouping");
        //    }

        //    Debug.Assert(grouping.Status != ChangeStatus.Complete);
        //}


        //private IMigrationAction createMigrationAction(
        //    Item changeItem,
        //    ChangeGrouping grouping,
        //    ChangeAction changeType)
        //{
        //    IMigrationAction action = grouping.CreateAction();

        //    action.SourceItem = new TfsMigrationItem(changeItem, Session);
        //    action.TargetTargetItem = CreateMigrationItem(changeItem);
        //    action.Action = changeType;

        //    return action;
        //}

        #endregion
    }
}